package com.aifast.system.sys.service;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.aifast.common.base.BaseEntity;
import com.aifast.common.base.Kv;
import com.aifast.common.base.R;
import com.aifast.common.cache.annotations.AutoCache;
import com.aifast.common.cache.util.RedisUtil;
import com.aifast.common.global.Const;
import com.aifast.common.layui.LayuiDataTable;
import com.aifast.common.layui.LayuiPageFactory;
import com.aifast.system.log.service.LogLoginService;
import com.aifast.system.sys.dao.SysUserDao;
import com.aifast.system.sys.dao.SysUserRoleDao;
import com.aifast.system.sys.entity.SysRole;
import com.aifast.system.sys.entity.SysUser;
import com.aifast.system.sys.entity.SysUserRole;
import com.aifast.system.sys.entity.UserInfo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author fujian
 * @since 2022-01-07
 */
@Service
@RequiredArgsConstructor
@AutoCache
public class SysUserService extends ServiceImpl<SysUserDao, SysUser> {

    private final SysUserDao dao;
    private final SysUserRoleDao sysUserRoleDao;
    private final SysRoleService sysRoleService;
    private final SysOrgService sysOrgService;
    private final StpInterfaceService stpInterfaceService;
    private final LogLoginService logLoginService;

    /**
     * layui数据表格列表查询方法
     *
     * @param search 关键字搜索
     * @param orgId  组织架构
     * @param state  状态
     * @param page   分页
     * @return 列表数据
     */
    public LayuiDataTable list(String search, Integer orgId, Integer state, Integer roleId, Page page) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StrUtil.isNotBlank(search),SysUser::getRealName,search).or().like(StrUtil.isNotBlank(search),SysUser::getUsername,search);
        wrapper.in(ObjectUtil.isNotNull(orgId),SysUser::getOrgId,sysOrgService.getChildrenIds(orgId));
        wrapper.in(ObjectUtil.isNotNull(roleId), BaseEntity::getId,sysUserRoleDao.selectList(new QueryWrapper<SysUserRole>().eq("role_id",roleId)).stream().map(SysUserRole::getUserId).collect(Collectors.toList()));
        wrapper.eq(ObjectUtil.isNotNull(state),SysUser::getState,state);
//        Page<SysUser> pages = dao.list(search, sysOrgService.getChildrenIds(orgId), state, roleId, page);
        Page<SysUser> pages = page(page, wrapper);
        pages.getRecords().forEach(i->{
//            i.setPhone(DesensitizedUtil.mobilePhone(i.getPhone()));
            List<SysRole> roles = sysRoleService.getRoles(i.getId());
            i.setRoles(roles);
        });
        return LayuiPageFactory.init(pages);
    }

    /**
     * 新增或者查询
     * <br>vo的方法另写，里面有判定是否新增还是修改 可自定义逻辑
     *
     * @param sysUser
     * @param roleIds
     * @param diyLabel
     * @return
     */
    public Boolean insertOrUpdate(SysUser sysUser, String roleIds, String diyLabel) {
        if (ObjectUtil.isNull(sysUser.getId())) {

        }
        if (StrUtil.isNotBlank(diyLabel)) {
            String s = StrUtil.replaceIgnoreCase(diyLabel, " ", Const.SYMBOL_COMMA);
            sysUser.setLabel(s);
        }
        if(StrUtil.isBlank(sysUser.getPassword())){
            sysUser.setPassword(null);
        }
        if (!saveOrUpdate(sysUser)) {
            return false;
        }
        if (StrUtil.isNotBlank(roleIds)) {
            sysUserRoleDao.delete(new QueryWrapper<SysUserRole>().eq("user_id", sysUser.getId()));
            if (StrUtil.isNotBlank(roleIds)) {
                Integer[] integers = Convert.toIntArray(roleIds.split(","));
                for (Integer i : integers) {
                    sysUserRoleDao.insert(SysUserRole.builder().userId(sysUser.getId()).roleId(i).build());
                }
            }
        }

//        UserInfo.remove(sysUser.getId().toString());
        return true;
    }

    /**
     * 删除方法
     * <br>提供单个删除和批量删除
     *
     * @param id  数据id
     * @param ids 数据id集合
     * @return
     */
    public Boolean del(Integer id, String ids) {
        List<Integer> integers = new ArrayList<>();
        if (StrUtil.isNotBlank(ids)) {
            integers = Convert.toList(Integer.class, ids.split(","));
        }
        if (ObjectUtil.isNotNull(id)) {
            integers.add(id);
        }
        try {
            integers.forEach(i -> {
                update(new UpdateWrapper<SysUser>().set("deleted", 1).eq("id", i));
            });

            UserInfo.remove(id.toString());

            return true;
        } catch (Exception e) {
            return false;
        }


    }

    /**
     * 数据详情
     *
     * @param id 数据id
     * @return
     */
    public SysUser info(Integer id) {
        if (ObjectUtil.isNull(id)) return null;
        SysUser one = getOne(new QueryWrapper<SysUser>()
                .eq("id", id));

        return one;
    }

    /**
     * 重置密码
     *
     * @param userId 用户id
     * @return
     */
    public boolean resetPsw(Integer userId) {
        SysUser user = getById(userId);
        if (ObjectUtil.isNull(user)) {
            return false;
        }
        user.setPassword("123456");
        return updateById(user);

    }

    /**
     * 修改用户状态
     *
     * @param userId 用户id
     * @param state  状态
     * @return
     */
    public boolean updateUserState(Integer userId, Integer state) {
        SysUser user = getById(userId);
        if (ObjectUtil.isNull(user)) {
            return false;
        }
        user.setState(state);
        return updateById(user);
    }

    /**
     * 获取个人信息
     * @return
     */
    public Object personal() {
        return UserInfo.get();

    }

    /**
     * 修改头像
     * @param img
     * @return
     */
    public String updateAvatar(String img) {

        if (StrUtil.isBlank(img)) {
            return null;
        }

        String base64Img;
        if (StrUtil.contains(img, "data:image/jpeg;base64,")) {
            base64Img = StrUtil.replace(img, "data:image/jpeg;base64,", "");
        } else if (StrUtil.contains(img, "data:image/png;base64,")) {
            base64Img = StrUtil.replace(img, "data:image/png;base64,", "");
        } else {
            return null;
        }


        byte[] decode = Base64.decode(base64Img);
        String path = StrUtil.join("", Const.CURRTPATH, "/images/head/");
        File file = new File(path);
        if (!file.exists()) {
            FileUtil.mkdir(file);
        }
        String fileName = StrUtil.join("", UserInfo.get().getUsername(), ".jpg");
        File writeBytes = FileUtil.writeBytes(decode, StrUtil.join("", path, fileName));

        if (StrUtil.isBlank(writeBytes.getName())) {
            return null;
        }
        SysUser sysUser = dao.selectById(UserInfo.get().getUserId());
        sysUser.setAvatar(StrUtil.join("", "/view/images/head/", writeBytes.getName()));

        return updateById(sysUser) ? sysUser.getAvatar() : null;

    }

    /**
     * 修改密码
     * @param password 原密码
     * @param newPassword 新密码
     * @param confirmNewPassword 确认新密码
     * @return
     */
    public R updatePassword(String password, String newPassword, String confirmNewPassword) {
        if(StrUtil.isBlank(password) || StrUtil.isBlank(newPassword) || StrUtil.isBlank(confirmNewPassword)){
            return R.ERROR();
        }
        if(StrUtil.equals(password,newPassword)){
            return R.ERROR("旧密码和新密码不能相同");
        }
        if(!StrUtil.equals(newPassword,confirmNewPassword)){
            return R.ERROR("新密码确认失败");
        }
        SysUser sysUser = dao.selectById(UserInfo.get().getUserId());
        if(!StrUtil.equals(password,sysUser.getPassword())){
            return R.ERROR("旧密码错误");
        }
        sysUser.setPassword(newPassword);
        return updateById(sysUser) ? R.OK() : R.ERROR();
    }

    /**
     * 用户登录逻辑
     * @param username  账号
     * @param password 密码
     * @param code 验证码
     * @param sessionId
     * @param request
     * @return
     */
    public SaResult login(String username, String password, String code, String sessionId, HttpServletRequest request) {
        if(StrUtil.isBlank(username)){
            return SaResult.error("账户不能为空！！！");
        }
        if(StrUtil.isBlank(password)){
            return SaResult.error("密码不能为空！！！");
        }
        if(StrUtil.isBlank(code)){
            return SaResult.error("验证码不能为空！！！");
        }
        String key = StrUtil.join(Const.SYMBOL_COLON,"login",sessionId);
        if(!RedisUtil.exists(key)){
            return SaResult.error("验证码过期，请按F5刷新页面");
        }
        String s = (String) RedisUtil.get(key);
        if(!StrUtil.equals(code,s)){
            return SaResult.error("验证码错误!!!");
        }

        try {
            SysUser one = dao.getByUserNameAndPassword(username,SecureUtil.md5(password));
            if(ObjectUtil.isNull(one)){
                return SaResult.error("账号或密码错误");
            }
            StpUtil.login(one.getId(),Const.PC);
            stpInterfaceService.createCurrentUserInfo(one);

            logLoginService.putLog(one,request);
            return SaResult.ok("登录成功").setCode(0).setData(putMap(StpUtil.getTokenInfo())) ;
        }catch (Exception e){
            e.printStackTrace();
            return SaResult.error("账户异常，请联系管理员");
        }
    }

    private Map putMap(SaTokenInfo info){
        Map<String, Object> map = Convert.toMap(String.class, Object.class, info);
        map.put("perms",UserInfo.get().getAuthorities());
        return map;
    }


    public List<Kv> selectData() {
        List<SysUser> list = list();
        List<Kv> res = new ArrayList<>();
        list.forEach(i->{
            Kv kv = Kv.build().set("id", i.getId()).set("name", i.getRealName());
            res.add(kv);
        });
        return res;
    }
}
